package org.light.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.light.utils.DomainTokenUtil;
import org.light.utils.StringUtil;

public class Field implements Comparable<Object>,Cloneable,Serializable  {
	private static final long serialVersionUID = -3468420836142040982L;
	protected long serial = 0L;
	protected Type fieldType = new Type();
	protected String fieldName;
	protected String fieldComment;
	protected String fieldValue;
	protected List<String> tokens = new ArrayList<String>();
	protected Set<String> annotations = new TreeSet<String>();	
	protected String label;
	protected boolean fixed = false;
	protected String originalType ="";
	protected String lengthStr = "";
	protected String fixedName = "";
	
	public void setSerial(long serial) {
		this.serial = serial;
	}

	public String getFieldValue() {
		return fieldValue;
	}
	
	public Type getFieldRawType(){
		return this.fieldType;
	}

	public void setFieldValue(String fieldValue) {
		this.fieldValue = fieldValue;
	}

	public Set<String> getAnnotations() {
		return annotations;
	}

	public void setAnnotations(Set<String> annotations) {
		this.annotations = annotations;
	}
	
	public void addAnnotation(String annotation){
		this.annotations.add(annotation);
	}

	public void setFieldType(Type fieldType) {
		this.fieldType = fieldType;
	}


	public String getFieldComment() {
		return fieldComment;
	}

	public void setFieldComment(String fieldComment) {
		this.fieldComment = fieldComment;
	}

	public List<String> getTokens() {
		return tokens;
	}

	public void setTokens(List<String> tokens) {
		this.tokens = tokens;
	}

	public String getFieldName() {
		return fieldName;
	}

	public void setFieldName(String fieldName) {
		this.fieldName = fieldName;
	}

	public Field() {
		super();
	}

	public Field(String fieldName, Type type) {
		super();
		this.fieldName = fieldName;
		this.fixedName = fieldName;
		this.fieldType = type;
	}
	
	public Field(String fieldName, String fixedName,Type type) {
		super();
		this.fieldName = fieldName;
		this.fixedName = fixedName;
		this.fieldType = type;
	}
	
	public Field(String fieldName, String typeString) {
		super();
		this.fieldName = fieldName;
		this.fixedName = fieldName;
		this.fieldType = new Type(typeString);
	}
	
	public Field(String fieldName, String fixedName,String typeString) {
		super();
		this.fieldName = fieldName;
		this.fixedName = fixedName;
		this.fieldType = new Type(typeString);
	}
	
	public Field(long serial,String fieldName, String typeString,String fieldLengthStr) {
		super();
		this.serial = serial;
		this.fieldName = fieldName;
		this.fixedName = fieldName;
		this.fieldType = new Type(typeString);
		this.lengthStr = fieldLengthStr;
	}
	
	public Field(long serial,String fieldName, String fixName,String typeString,String fieldLengthStr) {
		super();
		this.serial = serial;
		this.fieldName = fieldName;
		this.fixedName = fixName;
		this.fieldType = new Type(typeString);
		this.lengthStr = fieldLengthStr;
	}
	
	public Field(int serial,String fieldName, Type type,String fieldLengthStr) {
		super();
		this.serial = serial;
		this.fieldName = fieldName;
		this.fixedName = fieldName;
		this.fieldType = type;
		this.lengthStr = fieldLengthStr;
	}
	
	public Field(String fieldName,String typeString,String packageToken,String fieldLengthStr){
		super();
		this.fieldName = fieldName;
		this.fixedName = fieldName;
		this.fieldType = new Type(typeString, packageToken);
		this.lengthStr = fieldLengthStr;
	}
	
	public Field(String fieldName,String typeString,String packageToken, String fieldValue,String fieldLengthStr){
		super();
		this.fieldName = fieldName;
		this.fixedName = fieldName;
		this.fieldType = new Type(typeString, packageToken);
		this.fieldValue = fieldValue;
		this.lengthStr = fieldLengthStr;
	}
	
	
	public Field(int serial,String fieldName, Type type,String packageToken,String fieldLengthStr) {
		super();
		this.serial = serial;
		this.fieldName = fieldName;
		this.fixedName = fieldName;
		this.fieldType = type;
		this.setPackageToken(packageToken);
		this.lengthStr = fieldLengthStr;
	}
	
	@Override
	public int compareTo(Object o) {
		int result = this.fieldName.compareTo(((Field)o).getFieldName());
		if (result == 0) {
			return  this.getClassType().compareTo(((Field)o).getClassType());
		}else{
			return result;
		}
	}
	
	@Override
	public boolean equals(Object o){
		return this.getFieldName().equals(((Field)o).getFieldName());
	}
	
	public String getFieldTableColumName(){
		StringBuilder sb = new StringBuilder(this.fieldName);
		StringBuilder sb0 = new StringBuilder("");
		boolean continueCap = false;
		for(int i=0; i < sb.length(); i++){
			char ch = sb.charAt(i);
			if (ch<='Z'&& ch>='A'&&i>0&&!continueCap){
				sb0.append("_").append((""+ch).toLowerCase());
				continueCap = true;
			}else if (ch<='Z'&& ch>='A'&&i==0){
				sb0.append((""+ch).toLowerCase());
				continueCap = true;
			} else if (ch<='Z'&& ch>='A'&&continueCap){
				sb0.append((""+ch).toLowerCase());
			}else if (ch<='z'&& ch>='a') {
				sb0.append(ch);
				continueCap = false;
			}else {
				sb0.append(ch);
			}
		}
		return sb0.toString();
	}
	
	public long getSerial() {
		return serial;
	}

	public void setSerial(int serial) {
		this.serial = serial;
	}

	public String getFieldType() {
		return fieldType.getTypeName();
	}
	
	public String getOracleFieldType() {
		return Type.getOracleClassType(fieldType.getTypeName()).getTypeName();
	}

	public void setFieldType(String fieldType) {
		this.fieldType = new Type(fieldType);
	}
	
	public void setPackageToken(String packageToken){
		this.fieldType.setPackageToken(packageToken);
	}
	
	public String getPackageToken(){
		return this.fieldType.getPackageToken();
	}
	
	public String getGetterCall(){
		if (fieldType.getTypeName().equalsIgnoreCase("boolen")) return "is"+StringUtil.capFirst(this.getFieldName())+"()";
		else return "get"+StringUtil.capFirst(this.getFieldName())+"()";
	}
	
	public String getGetterCallName(){
		if (fieldType.getTypeName().equalsIgnoreCase("boolen")) return "is"+StringUtil.capFirst(this.getFieldName());
		else return "get"+StringUtil.capFirst(this.getFieldName());
	}
	
	public String getSetterCallName(){
		return "set"+StringUtil.capFirst(this.getFieldName());
	}
	
	public String getLowerFirstFieldName(){
		return StringUtil.lowerFirst(this.getFieldName());
	}
	
	public String getCapFirstFieldName(){
		return StringUtil.capFirst(this.getFieldName());
	}
	
	public String getTableColumnName(){
		return StringUtil.changeDomainFieldtoTableColum(this.getLowerFirstFieldName());
	}
	
	public Type getRawType() {
		return this.fieldType;
	}
	
	public String getLabel() {
		return label;
	}

	public void setLabel(String label) {
		this.label = label;
	}
	
	public String getText(){
		if (this.label!= null && !this.label.equals("")) return this.label;
		else return this.fieldName;
	}
	
	public Type getClassType() {
		if ("int".equalsIgnoreCase(getFieldType())) return new Type("Integer");
		else if ("Integer".equalsIgnoreCase(getFieldType())) return new Type("Integer");
		else if ("long".equalsIgnoreCase(getFieldType())) return new Type("Long");
		else if ("boolean".equalsIgnoreCase(getFieldType())) return new Type("Boolean");
		else if ("float".equalsIgnoreCase(getFieldType())) return new Type("Float");
		else if ("double".equalsIgnoreCase(getFieldType())) return new Type("Double");
		else if ("image".equalsIgnoreCase(getFieldType())) return new Type("byte []");
		else return this.fieldType;
	}
	
	public Type getOracleClassType() {
		if ("int".equals(getFieldType())) return new Type("Integer");
		else if ("long".equals(getFieldType())) return new Type("String");
		else if ("boolean".equals(getFieldType())) return new Type("Integer");
		else if ("float".equals(getFieldType())) return new Type("Float");
		else if ("double".equals(getFieldType())) return new Type("Double");
		else return this.fieldType;
	}
	
	public Type getOraclePlsqlType() {
		if ("int".equalsIgnoreCase(getFieldType())) return new Type("Integer");
		if ("Integer".equalsIgnoreCase(getFieldType())) return new Type("Integer");
		if ("long".equalsIgnoreCase(getFieldType())) return new Type("varchar2(32)");
		else if ("boolean".equalsIgnoreCase(getFieldType())) return new Type("Integer");
		else if ("float".equalsIgnoreCase(getFieldType())) return new Type("number(10,4)");
		else if ("double".equalsIgnoreCase(getFieldType())) return new Type("number(10,4)");
		else if ("BigDecimals".equalsIgnoreCase(getFieldType())) return new Type("number(10,4)");
		else if ("String".equalsIgnoreCase(getFieldType())&&(getFieldName().toLowerCase().contains("description")||getFieldName().toLowerCase().contains("content"))) return new Type("varchar2(2000)");
		else if ("String".equalsIgnoreCase(getFieldType())&&!(getFieldName().toLowerCase().contains("description")||getFieldName().toLowerCase().contains("content"))) return new Type("varchar2(255)");
		else return this.fieldType;
	}
	
	public String getFeildNameAsTableColumn(){
		return DomainTokenUtil.changeDomainFieldtoTableColum(getFieldName());
	}
	
	public Object clone() {
		Field o = null;
		try {
			o = (Field) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return o;
	}

	public boolean isFixed() {
		return fixed;
	}

	public void setFixed(boolean fixed) {
		this.fixed = fixed;
	}

	public String getOriginalType() {
		return originalType;
	}

	public void setOriginalType(String originalType) {
		this.originalType = originalType;
	}
	
	public boolean isTextarea() {
		if (this.fieldName.toLowerCase().contains("content")||this.fieldName.toLowerCase().contains("description")||this.fieldName.toLowerCase().contains("comment")) {
			return true;
		}else {
			return false;
		}
	}

	public String getLengthStr() {
		return lengthStr;
	}

	public void setLengthStr(String lengthStr) {
		this.lengthStr = lengthStr;
	}

	public String getFixedName() {
		return fixedName;
	}

	public void setFixedName(String fixedName) {
		this.fixedName = fixedName;
	}
}
